package socket.protocol;

import io.reactivex.schedulers.Schedulers;
import socket.PLCFactory;
import socket.modle.ConnectedCallback;
import socket.modle.PlcInterface;
import socket.util.ByteUtil;
import socket.util.SLog;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.SocketException;
import java.util.TimerTask;

/**
 * Created by bpb on 2021-01-17.
 * 说明：TCP 版本
 */
public class ProtocolServerType4 extends IProtocolServer implements ConnectedCallback {

    public String TAG = "TCP";
    private PlcInterface plcInterface;
    private Object mSendLock = new Object();


    public ProtocolServerType4(OnNeedCallback callback) {
        super(callback);
    }

    @Override
    public void onConnectedStatusChange(String key, boolean connected, Exception e, String msg) {
        SLog.getInstance().e_s("连接状态 key"+key+" connected:"+ connected + "，描述: " + msg);
        onNeedCallback.onConnectedStatusChanged(key, connected, e, msg);
    }

    private   byte[] start = new byte[2];
    private  byte[] standard = new byte[13];
    @Override
    public byte[] onReceive(final String key, DataInputStream dataInputStream) {
        try {

            int count = dataInputStream.available();
            if (count == 0) {
                return null;
            }
            int length = dataInputStream.read(start);
            if (length == -1) {
                disConnect();
                return null;
            }
            if (length != 2) {
                SLog.getInstance().e_s("标准头信息长度错误:" + length+"  ====key "+key);
                return null;
            }
            // 检查头信息
            if (start[0] != headerA || start[1] != headerB) {
                SLog.getInstance().e_s(key+" | "+System.currentTimeMillis()+"[TIME] 头信息错误：" + headerA + "|| " + headerB + " 原始数据： "
                        + ByteUtil.byteToHexString(start[0])+" "+ByteUtil.byteToHexString(start[1])+" KEy:"+key);
                return null;
            }

            length = dataInputStream.read(standard);
            if (length != 13) {
                SLog.getInstance().e_s("标准信息长度错误:" + length+"  ====key "+key);
                return null;
            }
//                StringBuilder logBuilder = new StringBuilder();
//                logBuilder.append("接收 <<< ");
//                logBuilder.append(headerA);
//                logBuilder.append(" " + headerB);
//                for (int i = 0; i < standard.length; i++) {
//                    logBuilder.append(" " + ByteUtil.byteToHexString(standard[i]));
//                }

            int action = ByteUtil.byteToInt(standard[0]);
            long rTime = ByteUtil.byteArrayToLong(new byte[]{standard[1], standard[2], standard[3], standard[4],standard[5],
                    standard[6],standard[7],standard[8]});
            int byteCount = ByteUtil.getInt(new byte[]{standard[9], standard[10], standard[11], standard[12]});
            byte[] content = getDataAndCheck(dataInputStream, byteCount, null);
        //     System.out.println(System.currentTimeMillis()+"[TIME] "+logBuilder.toString());
//            Schedulers.computation().scheduleDirect(new Runnable() {
//                @Override
//                public void run() {
                    onNeedCallback.checkAction(key, action, rTime, content);
//                }
//            });
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 读取内容字节并校验长度是否正确
     */
    private byte[] getDataAndCheck(DataInputStream inputStream, int dataLength, StringBuilder logBuilder) throws IOException {
        if (dataLength == 0) {
            return null;
        }
        byte[] data = new byte[dataLength];
        int length = inputStream.read(data);

        if (length != dataLength) {
            SLog.getInstance().e_s("内容长度错误:" + length + " != " + dataLength);
            return null;
        }
        if (logBuilder != null) {
            for (int i = 0; i < data.length; i++) {
                logBuilder.append(" " + ByteUtil.byteToHexString(data[i]));
            }
        }
        return data;
    }

    public long getSendTime(){
        return System.currentTimeMillis();
    }

    /**
     * 创建socket服务器并等待客户端连接
     *
     * @param retryCount 创建失败时重试的次数
     * @param params     创建通讯方式的参数
     */
    public void connect(int retryCount, Object... params) {
        synchronized (mSendLock) {
            plcInterface = PLCFactory.getPlcUtil(PLCFactory.SOCKET_CLIENT, TAG).init(this, retryCount);
        }
        plcInterface.connect(params);
    }

    public void sendData(String key, int cmd, byte[] bytes) {
        try {
            long rTime = getSendTime();
            byte[] tBytes = ByteUtil.toByteArray(rTime);
            int len = bytes == null ? 0 : bytes.length;
            byte[] datas = new byte[7 + len + 8];
            datas[0] = headerA;
            datas[1] = headerB;
            datas[2] = ByteUtil.intToByte(cmd);
            System.arraycopy(tBytes, 0, datas, 3, 8);
            datas[11] = (byte) ((len & 0xff000000) >> 24);
            datas[12] = (byte) ((len & 0xff0000) >> 16);
            datas[13] = (byte) ((len & 0xff00) >> 8);
            datas[14] = (byte) (len & 0xff);
            if (bytes != null) {
                System.arraycopy(bytes, 0, datas, 15, len);
            }
            sendData(key, datas);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    void sendData(String key, byte[] datas) {
        if (plcInterface != null) {
            plcInterface.sendData(key, datas);
        }
    }


    /**
     * 退出程序
     */
    public void destroy(String who) {
        synchronized (mSendLock) {
            if (plcInterface != null) {
                plcInterface.destroy(who);
            }
            plcInterface = null;
        }
    }


    @Override
    public void disConnect() {
     //   plcInterface.destroy();
        //  heartTimer.cancel();
    }


}
